/*
 * @Author: wangcb
 * @Email: wangcbgg@163.com
 * @Date: 2021-08-28 16:04:32
 * @LastEditTime: 2021-11-17 11:15:08
 * 标准弹框toast
 */
import extentDOM from "../helpers/extentDOM";
import { $, $$ } from "../helpers/selector";
import slideOld from "../helpers/slideOld";
import { supportCss3 } from "../helpers/util";
/**
 * Toast弹窗类
 * @class Toast
 */
class Toast {
    constructor() {
        /**
         * 弹框锁
         * @private
         * @type {boolean}
         */
        this.lock = false;
        /**
         * 弹框提示信息
         * @type {string}
         * @default ''
         */
        this.msg = '';
        /**
         * 页面弹框最大个数
         * @type {number}
         * @default 1
         */
        this.maxCount = 1;
        /**
         * 容器id
         * @type {string}
         * @default '-default-'
         */
        this.containerId = '-default-';
        /**
         * 宽度
         * @type {string}
         * @default 'auto'
         */
        this.width = 'auto';
        /**
         * 超时隐藏的毫秒数
         * @type {number}
         * @default 3000
         */
        this.timeout = 3000;
        /**
         * 圆角度radius
         * @type {string}
         * @default '5px'
         */
        this.borderRadius = '5px';
        /**
         * 背景
         * @type {string}
         * @default 'rgba(35, 35, 35, 0.9)'
         */
        this.background = 'rgba(35, 35, 35, 0.9)';
        /**
         * 文字对齐方式
         * @type {TAlign}
         * @default 'center'
         */
        this.align = 'center';
        /**
         * 内边距
         * @type {string}
         * @default '30px 100px'
         */
        this.padding = '30px 100px';
        /**
         * 外边距值
         * @type {string}
         * @default '25px'
         */
        this.margin = '25px';
        /**
         * 显示浮动距离
         * @type {number}
         * @default 100
         */
        this.floatHeight = 100;
        /**
         * 偏移间距
         * @type {number}
         * @default 20
         */
        this.floatSpacing = 20;
        /**
         * 字体大小
         * @type {string}
         * @default '30px'
         */
        this.fontSize = '30px';
        /**
         * 文字颜色
         * @type {string}
         * @default '#fff'
         */
        this.color = '#ffffff';
        /**
         * 显示位置
         * @type {TPosition}
         * @default 'bottom-center'
         */
        this.position = 'bottom-center';
        /**
         * 是否淡入淡出
         * @type {boolean}
         * @default false
         */
        this.fade = false;
        /**
         * 最终拼装样式
         * @default {}
         * @private
         */
        this.css = {};
    }
    /**
     * 获取Toast单实例
     * @description 单例模式保证持有单一实例
     * @returns {Toast}
     */
    static getInstance() {
        if (!this.instance)
            this.instance = new Toast();
        return this.instance;
    }
    /**
     * Toast弹窗配置定义
     * @typedef IToastConfig
     * @property {string} msg 弹框提示信息
     * @property {number} [maxCount=1] 页面弹框最大个数
     * @property {string} [containerId='-default-'] 容器id
     * @property {string} [width='auto'] 宽度
     * @property {number} [timeout=3000] 超时隐藏的毫秒数
     * @property {string} [borderRadius='5px'] 圆角度radius
     * @property {string} [background='rgba(35, 35, 35, 0.9)'] 背景
     * @property {TAlign} [align='center'] 文字对齐方式
     * @property {string} [padding='30px 100px'] 内边距
     * @property {string} [margin='25px'] 外边距
     * @property {number} [floatHeight=100] 显示浮动距离
     * @property {number} [floatSpacing=20] 偏移间距
     * @property {string} [fontSize='30px'] 字体大小
     * @property {string} [color='#ffffff'] 文字颜色
     * @property {TPosition} [position='bottom-center'] 显示位置
     */
    /**
     * 配置toast参数
     * @param {IToastConfig} config 配置参数
     * @returns {Toast}
     */
    setConfig(config) {
        if (config && typeof config === 'object') {
            if (config.maxCount)
                this.maxCount = config.maxCount; // 页面弹框最大个数
            if (config.msg)
                this.msg = config.msg; // 提示信息
            if (config.containerId)
                this.containerId = config.containerId; // 容器id
            if (config.width)
                this.width = config.width; // 宽度
            if (config.timeout)
                this.timeout = config.timeout; // 超时隐藏的毫秒数
            if (config.borderRadius)
                this.borderRadius = config.borderRadius; // 圆角度radius
            if (config.background)
                this.background = config.background; // 背景
            if (config.align)
                this.align = config.align; // 文字对齐方式
            if (config.padding)
                this.padding = config.padding; // 内边距
            if (config.margin)
                this.margin = config.margin; // 外边距
            if (config.floatHeight)
                this.floatHeight = config.floatHeight; // 显示浮动距离
            if (config.floatSpacing)
                this.floatSpacing = config.floatSpacing; // 偏移间距
            if (config.fontSize)
                this.fontSize = config.fontSize; // 字体大小
            if (config.color)
                this.color = config.color; // 文字颜色
            if (config.position)
                this.position = config.position; // 显示位置
        }
        this.css = {}; // 最终拼装样式
        this.$init(); // 初始化样式
        return this;
    }
    /**
     * 初始化样式
     * @private
     */
    $init() {
        this.css = {
            'width': this.width,
            'border-radius': this.borderRadius,
            'background': this.background,
            'text-align': this.align,
            'padding': this.padding,
            'font-size': this.fontSize,
            'color': this.color,
            'z-index': '99999',
            'position': 'fixed',
            'white-space': 'nowrap',
            'will-change': 'transform'
        };
        switch (this.position) { // 计算位置
            case 'top-left':
                this.css['top'] = '0', this.css['left'] = '0', this.css['margin'] = this.margin;
                break;
            case 'top-center':
                this.css['top'] = '0', this.css['left'] = '50%', this.css['margin-top'] = this.margin;
                break;
            case 'top-right':
                this.css['top'] = '0', this.css['right'] = '0', this.css['margin'] = this.margin;
                break;
            case 'bottom-left':
                this.css['bottom'] = '0', this.css['left'] = '0', this.css['margin'] = this.margin;
                break;
            case 'bottom-center':
                this.css['bottom'] = '0', this.css['left'] = '50%', this.css['margin-bottom'] = this.margin;
                break;
            case 'bottom-right':
                this.css['bottom'] = '0', this.css['right'] = '0', this.css['margin'] = this.margin;
                break;
            default: break;
        }
    }
    /** 执行toast */
    toast() {
        if (this.lock)
            return;
        this.lock = true;
        let container = document.body;
        if (this.containerId !== '-default-') {
            container = $(this.containerId); // 容器元素
            this.css.position = 'absolute';
        }
        const toast = document.createElement('div'); // 创建toast元素
        extentDOM(toast); // 扩展dom
        toast.style.cssText = JSON.stringify(this.css).replace(/(":"|':')/g, ':').replace(/(","|',')/g, ';').replace(/(\"|\{|\})/g, '');
        if (this.fade)
            toast.setOpacity(0);
        toast.className = 'toast-item';
        toast.innerHTML = this.msg;
        const toastItems = $$(toast.className, container);
        if (toastItems && toastItems.length > 0) {
            if (toastItems.length === this.maxCount)
                container.removeChild(toastItems[0]); // 移除已存在的第一个toast元素
            for (let i = 0; i < toastItems.length; i++) {
                const item = toastItems[i];
                const scrollHeight = item.scrollHeight;
                if (supportCss3('transform')) {
                    item.style.webkitTransition = 'all 400ms ease-in-out';
                    item.style.transition = 'all 400ms ease-in-out';
                    if (this.position.indexOf('top') !== -1) { // 重置定位
                        item.style.top = ~~(parseInt(item.getStyle('top'), 10) + scrollHeight + parseInt(this.margin, 10)) + 'px';
                    }
                    else if (this.position.indexOf('bottom') !== -1) {
                        item.style.bottom = ~~(parseInt(item.getStyle('bottom'), 10) + scrollHeight + parseInt(this.margin, 10)) + 'px';
                    }
                }
                else {
                    if (this.position.indexOf('top') !== -1) { // 重置定位
                        slideOld(item, { top: ~~(parseInt(item.getStyle('top'), 10) + scrollHeight + parseInt(this.margin, 10)), duration: 400 });
                    }
                    else if (this.position.indexOf('bottom') !== -1) {
                        slideOld(item, { bottom: ~~(parseInt(item.getStyle('bottom'), 10) + scrollHeight + parseInt(this.margin, 10)), duration: 400 });
                    }
                }
            }
        }
        container.appendChild(toast);
        if (this.position == undefined || this.position.indexOf('center') !== -1) { // 居中
            toast.style.marginLeft = -Math.ceil(toast.scrollWidth / 2) + 'px';
        }
        // 延迟执行回调
        const delay = (time, callback) => {
            const t = setTimeout(() => { clearTimeout(t), callback && callback(); }, time);
        };
        if (this.position.indexOf('bottom') !== -1) {
            delay(100, () => { this.fade ? toast.fadeIn() : toast.visible(), toast.slide(-this.floatHeight, 'v-bottom', 300, 0, 0); });
            delay(400, () => { this.lock = false, toast.slide(-this.floatHeight + this.floatSpacing, 'v-bottom', 300, 0, 0); });
        }
        else {
            delay(100, () => { this.fade ? toast.fadeIn() : toast.visible(), toast.slide(this.floatHeight, 'v', 300, 0, 0); });
            delay(400, () => { this.lock = false, toast.slide(this.floatHeight - this.floatSpacing, 'v', 300, 0, 0); });
        }
        delay(700 + this.timeout, () => { this.fade ? toast.fadeOut() : toast.unvisible(), toast.slide(0); });
        delay(1000 + this.timeout, () => { if (container.contains(toast))
            container.removeChild(toast); }); // 移除Toast
    }
    /**
     * 取消并移除toast
     * @memberof Toast
     */
    dismiss() {
        let container = document.body;
        if (this.containerId !== '-default-') {
            container = $(this.containerId); // 容器元素
        }
        const toasts = $$('toast-item', container);
        for (let i = 0; i < toasts.length; i++) {
            const toast = toasts[i];
            if (toast && container.contains(toast))
                container.removeChild(toast);
        }
    }
}
/**
 * Toast信息提示，入参为Toast配置对象或者msg信息字符串
 * @param {Toast | string} config Toast配置对象或者msg信息字符串
 * @example
 * showToast('这是toast提示');// 使用默认配置
 * showToast({
 *    msg: '这是toast提示',
 *    fontSize: '50px'
 * });// 使用自定义配置
 */
export function showToast(config) {
    const instance = Toast.getInstance();
    if (typeof config === 'object') {
        instance.setConfig(config).toast();
    }
    else {
        instance.setConfig({ msg: config }).toast();
    }
    return instance;
}
